package com.csun.cmny.provider.device.csun.sleep;

import com.csun.cmny.config.properties.CmnyProperties;
import com.csun.cmny.mqtt.constant.MqttMsgConstants;
import com.csun.cmny.mqtt.entity.*;
import com.csun.cmny.provider.controller.websocket.WebSocketUtils;
import com.csun.cmny.provider.dao.DmcCsunSleepCmdHiMapper;
import com.csun.cmny.provider.dao.DmcCsunSleepCmdMapper;
import com.csun.cmny.provider.device.csun.sleep.entity.*;
import com.csun.cmny.provider.device.csun.sleep.guokang.GuoKangData;
import com.csun.cmny.provider.device.csun.sleep.guokang.GuoKangPub;
import com.csun.cmny.provider.device.csun.sleep.minzheng.MinZhengPub;
import com.csun.cmny.provider.device.csun.sleep.minzheng.MqttPushServiceImpl;
import com.csun.cmny.provider.model.constant.*;
import com.csun.cmny.provider.model.domain.*;
import com.csun.cmny.provider.model.dto.device.DeviceBindDto;
import com.csun.cmny.provider.model.dto.device.DeviceStatus;
import com.csun.cmny.provider.model.enums.csunsleep.DmcCsunSleepBindTypeEnum;
import com.csun.cmny.provider.model.enums.device.DeviceStatusEnum;
import com.csun.cmny.provider.model.enums.device.DmcDeviceTypeEnum;
import com.csun.cmny.provider.model.vo.OldmanBedRoomBuildingVo;
import com.csun.cmny.provider.model.vo.csunsleep.DmcCsunSleepVo;
import com.csun.cmny.provider.model.vo.life.LifeTransducerConfigVO;
import com.csun.cmny.provider.service.*;
import com.csun.cmny.provider.utils.DeviceLogUtils;
import com.csun.cmny.provider.utils.DeviceUtils;
import com.csun.cmny.provider.utils.MqttMessageUtils;
import com.csun.cmny.util.DateUtil;
import com.csun.cmny.util.PublicUtil;
import com.csun.cmny.util.RedisKeyUtil;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.google.gson.JsonParseException;
import com.google.gson.JsonParser;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.MessagingException;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.TimeUnit;

/**
 * @Auther: chisj chisj@foxmal.com
 * @Date: 2019-03-05 20:41
 * @Description:
 */
@Slf4j
public class SleepMessageHandler implements MessageHandler {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    @Resource
    private DmcCsunSleepDataService dmcCsunSleepDataService;
    @Resource
    private DmcCsunSleepDataHiService dmcCsunSleepDataHiService;
    @Resource
    private DmcDeviceAlertService dmcDeviceAlertService;
    @Resource
    private DmcCsunSleepDataActionService dmcCsunSleepDataActionService;
    @Resource
    private SleepMessageGateway sleepMessageGateway;
    @Resource
    private DmcDeviceLogService dmcDeviceLogService;
    @Resource
    private DmcCsunSleepBindService dmcCsunSleepBindService;
    @Resource
    private DeviceUtils deviceUtils;
    @Resource
    private DmcCsunSleepFuncService dmcCsunSleepFuncService;
    @Resource
    private CmnyProperties cmnyProperties;
    @Resource
    private DmcCsunSleepDataInBedService dmcCsunSleepDataInBedService;
    @Resource
    private DmcCsunSleepThresholdService dmcCsunSleepThresholdService;
    @Resource
    private DmcDeviceService dmcDeviceSerivce;
    @Resource
    private DmcLifeTransducerDefaultConfigService dmcLifeTransducerDefaultConfigService;
    @Resource
    private DmcCsunSleepConfigService dmcCsunSleepConfigService;
    @Resource
    private DmcDeviceOnlineRecordService dmcDeviceOnlineRecordService;
    @Resource
    private WebSocketUtils webSocketUtils;
    @Resource
    private DmcCsunSleepCmdMapper dmcCsunSleepCmdMapper;
    @Resource
    private DmcCsunSleepCmdHiMapper dmcCsunSleepCmdHiMapper;
    @Resource
    private DmcCsunVersionSetDeviceService dmcCsunVersionSetDeviceService;
    @Resource
    private DmcDeviceService dmcDeviceService;
    @Resource
    private DeviceLogUtils deviceLogUtils;
    @Resource
    private GuoKangPub guoKangPub;
    @Resource
    private MinZhengPub minZhengPub;
    @Resource
    private MqttPushServiceImpl mqttPushService;
    @Resource
    private DmcGuoKangClientService dmcGuoKangClientService;

    public static CopyOnWriteArraySet<String> expireRedisKeySet = new CopyOnWriteArraySet<>();

    Gson gson = new Gson();

    private Integer ACTION_DURATION = 60 * 2;

    public SleepMessageHandler(Integer duration) {
        this.ACTION_DURATION = duration;
    }

    @Override
    public void handleMessage(Message<?> message) throws MessagingException {

        String msg = message.getPayload().toString();

        log.info("sleep message topic = {}", message.getHeaders().get("mqtt_receivedTopic"));
        log.info("sleep message qos = {}", message.getHeaders().get("mqtt_receivedQos"));
        log.info("sleep message = {}", msg);

        try {
            new JsonParser().parse(msg);
        } catch (JsonParseException e) {
            log.error("bad json: {} " + msg);
            return ;
        }

        String msgType = MqttMessageUtils.getMsgType(msg);
        if (PublicUtil.isEmpty(msgType)) {
            log.error("no msg type");
            return ;
        }

        switch (msgType) {
            case MqttMsgConstants.INVITE_HEAT :
                dealSleepHeat(msg);
                break;
            case MqttMsgConstants.INVITE_CLOSE :
                /**
                 * @date    2020-04-27
                 * @author  chisj
                 * @desc    统一采用心跳间隔监听床垫离线
                 */
                // dealSleepClose(msg);
                break;
            case MqttMsgConstants.SLEEP_BED_MSG :
                dealSleepBedMsg(msg);
                break;
            case MqttMsgConstants.SLEEP_BASIC_MSG :
                dealSleepBasicMsg(msg);
                break;
            case MqttMsgConstants.SLEEP_MSG :
                dealSleepMsg(msg);
                break;
            case MqttMsgConstants.SLEEP_ALARM_MSG :
                dealSleepAlarmMsg(msg);
                break;
            case MqttMsgConstants.SLEEP_CUR_VER_MSG :
                dealSleepCurVerMsg(msg);
                break;
            case MqttMsgConstants.SLEEP_UDT_VER_MSG :
                dealSleepUdtVerMsg(msg);
                break;
            case MqttMsgConstants.LOG_MSG :
                dealLogMsg(msg);
                break;
            case MqttMsgConstants.MQTT_VERSION_UPDATE_ACK_MSG :
                dealVerUpdateAckMsg(msg);
                break;
            case MqttMsgConstants.MQTT_UPDATE_STATUS_MSG :  // 版本升级状态消息
                dealUpdateStatusMsg(msg);
                break;
            case MqttMsgConstants.MQTT_SEND_DATA_ACK_MSG :
                dealSendDataAckMsg(msg);
                break;
            default:
                log.error("unknown msg type = {}", msgType);
                break;
        }
    }

    /**
     * 处理数据采集Ack
     *
     * @param msg
     */
    private void dealSendDataAckMsg(String msg) {

        MsgSendDataAck msgSendDataAck = gson.fromJson(msg, MsgSendDataAck.class);

        dealSleepMsgOk(MqttMsgConstants.MQTT_SEND_DATA_MSG, msgSendDataAck.getEventId(),
                msgSendDataAck.getMattessId());
    }

    /**
     * 处理收到版本升级状态指令
     *
     * @param msg
     */
    private void dealUpdateStatusMsg(String msg) {

        MsgUpdateStatus msgUpdateStatus = gson.fromJson(msg, MsgUpdateStatus.class);

        int stat = DeviceConstant.VERSION_SET_CMD_FAILED;

        if ("1".equals(msgUpdateStatus.getStatus())) {
            stat = DeviceConstant.VERSION_SET_CMD_SUCCESS;
        } else if ("-1".equals(msgUpdateStatus.getStatus())){
            stat = DeviceConstant.VERSION_SET_CMD_DOWN;
        }

        dmcCsunVersionSetDeviceService.updateByTaskId(msgUpdateStatus.getUpdateEventId(), stat);

        // TODO 暂时不回复ack
    }

    /**
     * 处理收到版本升级指令
     *
     * @param msg
     */
    private void dealVerUpdateAckMsg(String msg) {

        MsgUpdateVerAck msgUpdateVerAck = gson.fromJson(msg, MsgUpdateVerAck.class);

        dealSleepMsgOk(MqttMsgConstants.MQTT_VERSION_UPDATE_MSG, msgUpdateVerAck.getEventId(),
                msgUpdateVerAck.getSn());

        dmcCsunVersionSetDeviceService.updateByTaskId(msgUpdateVerAck.getEventId(), DeviceConstant.VERSION_SET_CMD_SEND);
    }

    /**
     * 处理床垫收到ack消息
     *
     * @param msgType
     * @param eventId
     * @param sn
     */
    private void dealSleepMsgOk(String msgType, String eventId, String sn) {

        DmcCsunSleepCmd dmcCsunSleepCmd = new DmcCsunSleepCmd();
        dmcCsunSleepCmd.setEventId(eventId);
        dmcCsunSleepCmd.setMsgType(msgType);
        dmcCsunSleepCmd.setDeviceNo(sn);
        dmcCsunSleepCmdMapper.delete(dmcCsunSleepCmd);

        DmcCsunSleepCmdHi dmcCsunSleepCmdHi = new DmcCsunSleepCmdHi();
        dmcCsunSleepCmdHi.setMsgType(msgType);
        dmcCsunSleepCmdHi.setEventId(eventId);
        dmcCsunSleepCmdHi.setDeviceNo(sn);
        dmcCsunSleepCmdHiMapper.sendOk(dmcCsunSleepCmdHi);
    }

    /**
     * 处理床垫心跳消息
     *
     * @param msg
     */
    public void dealSleepHeat(String msg) {

        MsgInviteHeat msgInviteHeat = gson.fromJson(msg, MsgInviteHeat.class);
        String sn = msgInviteHeat.getSn();

        CsunSleepData csunSleepData = (CsunSleepData) redisTemplate.opsForValue()
                .get(RedisKeyUtil.getCsunSleepKey(sn));

        if (PublicUtil.isNotEmpty(csunSleepData)) {

            /**
             * 设置在线过期时间
             */
            refreshCsunSleepOnline(csunSleepData);

            /**
             * @date    2020-05-14
             * @author  chisj
             * @desc    保存设备版本号
             */
            if (PublicUtil.isNotEmpty(msgInviteHeat.getVersion())) {
                updateDeviceVersion(msgInviteHeat.getVersion(), csunSleepData);
            }

            /*
            * 2020-03-12 xcr
            * 判断上传心跳的床垫是否已经缓存，没有则缓存
            * */
            if(!expireRedisKeySet.contains(RedisKeyUtil.getCsunSleepOnline(sn)))
                expireRedisKeySet.add(RedisKeyUtil.getCsunSleepOnline(sn));

            csunSleepData.setStatus(DeviceStatusEnum.ONLINE.getKey());

            redisTemplate.opsForValue().set(RedisKeyUtil.getCsunSleepKey(csunSleepData.getDeviceNo()),
                    csunSleepData);

            saveCsunSleepData(csunSleepData);

            dmcDeviceAlertService.sendSleepDataByDeviceId(csunSleepData.getDeviceId());

            publishCsunSleepData(csunSleepData);

            // 发送床垫离线命令
            sendSleepOffCmd(csunSleepData);
        } else {
            new RuntimeException("csun sleep not load... [" + sn + "]");

            // 设备编号升级
            if (PublicUtil.isNotEmpty(msgInviteHeat.getVersion())) {
                // dmcDeviceService.updateDeviceVersion(csunSleepData.getDeviceId(), msgInviteHeat.getVersion());
                dmcDeviceService.updateDeviceVersionByDeviceNo(msgInviteHeat.getSn(), msgInviteHeat.getVersion());
            }
        }

    }

    /**
     * 更新设备版本状态
     *
     * @param version
     * @param csunSleepData
     */
    private void updateDeviceVersion(String version, CsunSleepData csunSleepData) {

        if (!version.equals(csunSleepData.getDeviceVersion())) {

            dmcDeviceService.updateDeviceVersion(csunSleepData.getDeviceId(), version);

            // 版本替换
            csunSleepData.setDeviceVersion(version);
        }
    }

    /**
     * 发送智能床垫离线命令
     *
     * @param csunSleepData the csun sleep data
     */
    private void sendSleepOffCmd(CsunSleepData csunSleepData) {

        try {

            DmcCsunSleepCmd dmcCsunSleepCmd = new DmcCsunSleepCmd();
            dmcCsunSleepCmd.setDeviceId(csunSleepData.getDeviceId());
            dmcCsunSleepCmd.setDeviceNo(csunSleepData.getDeviceNo());
            List<DmcCsunSleepCmd> dmcCsunSleepCmdList = dmcCsunSleepCmdMapper.select(dmcCsunSleepCmd);
            if (PublicUtil.isEmpty(dmcCsunSleepCmd)) {
                return;
            }

            for (DmcCsunSleepCmd cmd : dmcCsunSleepCmdList) {
                try {
                    Thread.sleep(1000);
                } catch (Exception e) {
                    e.printStackTrace();
                }

                sleepMessageGateway.sendToMqtt(cmd.getDeviceNo(), cmd.getQos(), cmd.getContent());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    private void refreshCsunSleepOnline(CsunSleepData csunSleepData) {

        /**
         * @date    2020-03-26
         * @author  chisj
         * @desc    智能床垫绑定房间后才上线
         */
        DmcCsunSleepBind record = new DmcCsunSleepBind();
        record.setDeviceId(csunSleepData.getDeviceId());
        int count = dmcCsunSleepBindService.selectCount(record);
        if (count < 1) {
            log.warn("====> the csun sleep [{}] not bind.", csunSleepData.getDeviceNo());
            return;
        }

        String deviceNo = csunSleepData.getDeviceNo();
        CsunSleepData csunSleepData1  = (CsunSleepData) redisTemplate.opsForValue().get(RedisKeyUtil.getCsunSleepKey(deviceNo));

        if(PublicUtil.isNotEmpty(csunSleepData1)&&csunSleepData1.getStatus().equals(DeviceStatusEnum.OFFLINE.getKey())){
            dmcDeviceOnlineRecordService.insertRecordByDeviceNo(deviceNo,OnlineConstant.ON_LINE);
        }
        redisTemplate.opsForValue().set(RedisKeyUtil.getCsunSleepOnline(deviceNo),
                csunSleepData, DeviceConstant.DEVICE_SLEEP_ONLINE_EXPIRE, TimeUnit.SECONDS);
    }

    private void deleteCsunSleepLeaveBedKey(CsunSleepData csunSleepData) {
        String deviceNo = csunSleepData.getDeviceNo();
        String redisKey  = RedisKeyUtil.getCsunSleepLeaveBed(deviceNo);
        expireRedisKeySet.remove(redisKey);
        redisTemplate.delete(redisKey);
    }

    /**
     * 处理床垫离线消息
     *
     * @param msg
     */
    public void dealSleepClose(String msg) {

        MsgInviteClose msgInviteClose = gson.fromJson(msg, MsgInviteClose.class);
        String sn = msgInviteClose.getSn();

        CsunSleepData csunSleepData = (CsunSleepData) redisTemplate.opsForValue()
                .get(RedisKeyUtil.getCsunSleepKey(sn));

        if (PublicUtil.isNotEmpty(csunSleepData)) {

            String stat = csunSleepData.getStatus();

            csunSleepData.setStatus(DeviceStatusEnum.OFFLINE.getKey());
            csunSleepData.setInBed(0);
            csunSleepData.setHeartbeat(-1);
            csunSleepData.setBreath(-1);
            csunSleepData.setAction(1);

//            redisTemplate.opsForValue().set(RedisKeyUtil.getCsunSleepKey(csunSleepData.getDeviceNo()),
//                    csunSleepData);

            saveCsunSleepData(csunSleepData);

            dmcDeviceAlertService.sendSleepDataByDeviceId(csunSleepData.getDeviceId());

            publishCsunSleepData(csunSleepData);

            // 从在线变成离线才推送离线报警
            if (stat.equals(DeviceStatusEnum.ONLINE.getKey())) {

                /*
                 * 2020-03-18
                 * 床垫离线
                 * */
//                dmcDeviceAlertService.deviceOfflineAlert(sn);

                /*
                * 2020-03-12 xcr
                * 遗嘱离线推送改为redis失效key方式推送
                * */
               /*
                // 判断是否需要推送离线报警
                DmcCsunSleepFunc dmcCsunSleepFunc = new DmcCsunSleepFunc();
                dmcCsunSleepFunc.setGroupId(csunSleepData.getGroupId());
                dmcCsunSleepFunc.setFuncCode(CsunSleepConstant.OFF_LINE);
                dmcCsunSleepFunc = dmcCsunSleepFuncService.selectOne(dmcCsunSleepFunc);
                if (dmcCsunSleepFunc != null
                        && dmcCsunSleepFunc.getStat().equals(CsunSleepConstant.SLEEP_FUNC_ENABLE)) {
                    // 推送离线报警
                    DmcDeviceAlert dmcDeviceAlert = new DmcDeviceAlert();
                    OldmanBedRoomBuildingVo obrvo = new OldmanBedRoomBuildingVo();
                    Integer result = dmcDeviceAlertService.csunSleepAlertMsg(sn, dmcDeviceAlert, obrvo,
                            CsunSleepConstant.OFF_LINE);
                    log.info("=====> dmcDeviceAlert = {}", dmcDeviceAlert.toString());
                    if (result > 0) {
                        dmcDeviceAlertService.sendDeviceAlertMsg(dmcDeviceAlert, obrvo);
                    }
                }
                */

                // 从在线变离线 在离床状态变为离线
                saveCsunSleepData(csunSleepData);
            } else {
                log.warn("设备已经是离线状态");
            }
        } else {
            new RuntimeException("csun sleep not load... [" + sn + "]");
        }

    }

    /**
     * 处理床垫在床消息
     *
     * @param msg
     */
    public void dealSleepBedMsg(String msg) {

        MsgSleepBed msgSleepBed = gson.fromJson(msg, MsgSleepBed.class);
        String sn = msgSleepBed.getMattessId();

        CsunSleepData csunSleepData = (CsunSleepData) redisTemplate.opsForValue()
                .get(RedisKeyUtil.getCsunSleepKey(sn));

        if (PublicUtil.isNotEmpty(csunSleepData)) {

            /**
             * 设置在线过期时间
             */
            refreshCsunSleepOnline(csunSleepData);

            csunSleepData.setStatus(DeviceStatusEnum.ONLINE.getKey());
            int bed = msgSleepBed.getInBed();
            String status = "bed_touch";
            Integer breath = csunSleepData.getBreath();
            Integer heart = csunSleepData.getHeartbeat();

            //离床变在床，删除离床key
            if(csunSleepData.getInBed().equals(DmcConstant.CSUN_SLEEP_NOT_BED) && DmcConstant.CSUN_SLEEP_IN_BED == bed){
                deleteCsunSleepLeaveBedKey(csunSleepData);
            }

            if (DmcConstant.CSUN_SLEEP_NOT_BED == bed) {
                status = "bed_off";
                csunSleepData.setBreath(-1);
                csunSleepData.setHeartbeat(-1);

                // 在床 变成 离床
                if (DmcConstant.CSUN_SLEEP_IN_BED == (int) csunSleepData.getInBed()) {
                    // 判断是否需要推送离床报警
                    DmcCsunSleepFunc dmcCsunSleepFunc = new DmcCsunSleepFunc();
                    dmcCsunSleepFunc.setGroupId(csunSleepData.getGroupId());
                    dmcCsunSleepFunc.setFuncCode(CsunSleepConstant.OFF_BED);
                    dmcCsunSleepFunc = dmcCsunSleepFuncService.selectOne(dmcCsunSleepFunc);
                    if (dmcCsunSleepFunc != null
                            && dmcCsunSleepFunc.getStat().equals(CsunSleepConstant.SLEEP_FUNC_ENABLE)) {

                        // TODO 获取离床时间阈值
                        Long deviceId = csunSleepData.getDeviceId();
                        // 查询床垫阈值
                        DmcCsunSleepThreshold thresholdQuery = dmcCsunSleepThresholdService.selectByKey(deviceId);
                        if (thresholdQuery == null) {
                            DmcDevice dmcDevice = dmcDeviceSerivce.selectByKey(deviceId);
                            DmcLifeTransducerDefaultConfig dmcLifeTransducerDefaultConfig = dmcLifeTransducerDefaultConfigService.selectByKey(dmcDevice.getGroupId());
                            // TODO 如果阈值不为0, 则按照阈值设置redis失效时间
                            if(dmcLifeTransducerDefaultConfig != null && dmcLifeTransducerDefaultConfig.getLeaveBedMeasuringTimeInterval() > 0){
//                                int leaveBedAlertTime = dmcLifeTransducerDefaultConfig.getLeaveBedMeasuringTimeInterval()- LifeConstant.LEAVE_BED_ERROR > 0?dmcLifeTransducerDefaultConfig.getLeaveBedMeasuringTimeInterval() - LifeConstant.LEAVE_BED_ERROR:1;
                                int leaveBedAlertTime = dmcLifeTransducerDefaultConfig.getLeaveBedMeasuringTimeInterval();
                                String redisKey = RedisKeyUtil.getCsunSleepLeaveBed(csunSleepData.getDeviceNo());
                                /**
                                 * @author  chisj
                                 * @date    2020-11-19
                                 * @desc    离床监测间隔时间从秒改为分钟
                                 */
                                redisTemplate.opsForValue().set(redisKey, csunSleepData, leaveBedAlertTime, TimeUnit.MINUTES);
                                //将离床的设备号存起来
                                expireRedisKeySet.add(redisKey);
                            }
//                            else {
//                                redisTemplate.opsForValue().set(RedisKeyUtil.getCsunSleepLeaveBed(csunSleepData.getDeviceNo()),
//                                        csunSleepData, 1 , TimeUnit.SECONDS);
//                            }
                        }else{
                            if(thresholdQuery.getLeaveBedMeasuringTimeInterval() > 0){
//                                int leaveBedAlertTime = thresholdQuery.getLeaveBedMeasuringTimeInterval()- LifeConstant.LEAVE_BED_ERROR > 0?thresholdQuery.getLeaveBedMeasuringTimeInterval() - LifeConstant.LEAVE_BED_ERROR:1;
                                int leaveBedAlertTime = thresholdQuery.getLeaveBedMeasuringTimeInterval();
                                String redisKey = RedisKeyUtil.getCsunSleepLeaveBed(csunSleepData.getDeviceNo());
                                /**
                                 * @author  chisj
                                 * @date    2020-11-19
                                 * @desc    离床监测间隔时间从秒改为分钟
                                 */
                                redisTemplate.opsForValue().set(redisKey, csunSleepData, leaveBedAlertTime, TimeUnit.MINUTES);
                                //将离床的设备号存起来
                                expireRedisKeySet.add(redisKey);
                            }
                        }

                        /*
                        * 2020-01-06 by xcr
                         * 离床报警除了配置离床报警码，还需配置离床报警时间，设置为1s
                         * 离床报警除了配置离床报警码，还需配置离床报警时间，设置为1s
                        * */
//                        DmcDeviceAlert dmcDeviceAlert = new DmcDeviceAlert();
//                        OldmanBedRoomBuildingVo obrvo = new OldmanBedRoomBuildingVo();
//                        Integer result = dmcDeviceAlertService.csunSleepAlertMsg(sn, dmcDeviceAlert, obrvo,
//                                CsunSleepConstant.OFF_BED);
//                        log.info("=====> dmcDeviceAlert = {}", dmcDeviceAlert.toString());
//                        if (result > 0) {
//                            dmcDeviceAlertService.sendDeviceAlertMsg(dmcDeviceAlert, obrvo);
//                        }
                    }
                }

            }

            //如果是Life绑定，需要查看是否触发了离房报警
            DmcCsunSleepVo vo = dmcCsunSleepBindService.getCsunSleepBindByDeviceNo(sn);
            if(vo != null && vo.getBindType() != null && vo.getBindType() == DeviceConstant.DEVICE_BIND_TYPE_LIFE){
                //如果离床 查看是否需要离床报警
                if(DmcConstant.CSUN_SLEEP_NOT_BED == bed){
                    DmcDeviceAlert dmcDeviceAlert = new DmcDeviceAlert();
                    OldmanBedRoomBuildingVo obrvo = new OldmanBedRoomBuildingVo();
                    int i = dmcDeviceAlertService.checkOldmanInRoomAndAlert(vo.getRoomId(), vo.getGroupId(), DmcDeviceTypeEnum.CSUN_SLEEP.getIndex(), dmcDeviceAlert, obrvo);
                    if(i > 0){
                        dmcDeviceAlertService.sendDeviceAlertMsg(dmcDeviceAlert,obrvo);
                    }
                }

                /**
                 * @date    2020-03-25
                 * @author  chisj
                 * @desc    推送设备状态改变
                 */
                // 推送设备状态改变消息
                DeviceStatus deviceStatus = new DeviceStatus();
                deviceStatus.setDeviceId(csunSleepData.getDeviceId());
                deviceStatus.setGroupId(csunSleepData.getGroupId());
                deviceStatus.setDeviceNo(csunSleepData.getDeviceNo());
                deviceStatus.setMessage(String.format("设备%s检测到老人在离房状态改变", csunSleepData.getDeviceNo()));
                webSocketUtils.pushWebsocketMessageWithStatus(deviceStatus);
            }

            csunSleepData.setInBed(bed);
            csunSleepData.setAction(1);

            redisTemplate.opsForValue().set(RedisKeyUtil.getCsunSleepKey(csunSleepData.getDeviceNo()),
                    csunSleepData);
            saveCsunSleepData(csunSleepData);

            // TODO 将在床、离床数据入库
            /**
             * @data    2019-10-14
             * @author  chisj
             * @desc    存储在床、离床数据
             */
            saveCsunSleepInBedData(csunSleepData);

            dmcDeviceAlertService.sendSleepDataByDeviceId(csunSleepData.getDeviceId());
            publishCsunSleepData(csunSleepData);


            // bed_off - 离床
            // bed_touch - 在床

            publicGuoKang(csunSleepData.getDeviceNo(),
                    breath,
                    heart,
                    status);
        } else {
            new RuntimeException("csun sleep not load... [" + sn + "]");
        }
    }

    /**
     * 处理床垫实时消息
     *
     * @param msg
     */
    public void dealSleepBasicMsg(String msg) {

        MsgSleepBasic msgSleepBasic = gson.fromJson(msg, MsgSleepBasic.class);
        String sn = msgSleepBasic.getMattessId();

        CsunSleepData csunSleepData = (CsunSleepData) redisTemplate.opsForValue()
                .get(RedisKeyUtil.getCsunSleepKey(sn));


        if (PublicUtil.isNotEmpty(csunSleepData)) {

            /**
             * 设置在线过期时间
             */
            refreshCsunSleepOnline(csunSleepData);

            csunSleepData.setBreath(msgSleepBasic.getBreath());
            csunSleepData.setHeartbeat(msgSleepBasic.getHeartbeat());
            csunSleepData.setStatus(DeviceStatusEnum.ONLINE.getKey());
            csunSleepData.setInBed(1);

            //删除离床key
            if(redisTemplate.hasKey(RedisKeyUtil.getCsunSleepLeaveBed(csunSleepData.getDeviceNo()))){
                if (msgSleepBasic.getBreath() > 0 || msgSleepBasic.getHeartbeat() > 0 || csunSleepData.getInBed().equals(DmcConstant.CSUN_SLEEP_IN_BED)) {
                    deleteCsunSleepLeaveBedKey(csunSleepData);
                }
            }

            Long deviceId = csunSleepData.getDeviceId();
            DmcCsunSleepBind bind = dmcCsunSleepBindService.selectByKey(deviceId);
//            if(bind != null && bind.getBindType() == DeviceConstant.DEVICE_BIND_TYPE_LIFE){
                //判断在当前时间间隔内，是否已经推送过报警
                if (!redisTemplate.hasKey(RedisKeyUtil.getCsunSleepBreathAlert(sn))) {
//                if (!redisTemplate.hasKey(RedisKeyUtil.getCsunSleepBreathAlert(sn)) || !redisTemplate.hasKey(RedisKeyUtil.getCsunSleepHeartbeatAlert(sn))) {
                        //查询阈值配置
                    DmcCsunSleepThreshold threshold = dmcCsunSleepThresholdService.selectByKey(csunSleepData.getDeviceId());

                    int maxBreathThreshold = 0, minBreathThreshold = 0, maxHeartbeatThreshold = 0, minHeartbeatThreshold = 0, alertDurtion = 0;

                    //查询床垫报警间隔
                    DmcCsunSleepConfig config = dmcCsunSleepConfigService.selectByKey(csunSleepData.getDeviceId());
                    if (config != null) {
                        alertDurtion = config.getVitalMeasuringTimeInterval();
                    }

                    if (threshold != null) {
                        maxBreathThreshold = threshold.getMaxBreathThreshold();
                        minBreathThreshold = threshold.getMinBreathThreshold();
                        maxHeartbeatThreshold = threshold.getMaxHeartbeatThreshold();
                        minHeartbeatThreshold = threshold.getMinHeartbeatThreshold();
                        if (alertDurtion == 0) {
                            DmcDevice dmcDevice = dmcDeviceSerivce.selectByKey(csunSleepData.getDeviceId());
                            LifeTransducerConfigVO configVO = dmcLifeTransducerDefaultConfigService.getDefaultConfigByGroupId(dmcDevice.getGroupId());

                            alertDurtion = configVO.getVitalMeasuringTimeInterval();
                        }

                    } else {
                        DmcDevice dmcDevice = dmcDeviceSerivce.selectByKey(csunSleepData.getDeviceId());
                        LifeTransducerConfigVO configVO = dmcLifeTransducerDefaultConfigService.getDefaultConfigByGroupId(dmcDevice.getGroupId());

                        maxBreathThreshold = configVO.getBreathMaxTimes();
                        minBreathThreshold = configVO.getBreathMinTimes();
                        maxHeartbeatThreshold = configVO.getHeartbeatMaximum();
                        minHeartbeatThreshold = configVO.getHeartbeatMinimum();
                        alertDurtion = configVO.getVitalMeasuringTimeInterval();
                    }



                    /*
                     * 2020-01-08
                     * 心跳呼吸为一种报警
                     * 2020-03-03
                     * 又改为两种报警
                     * 2020-03-09
                     * 又改为一种报警
                     * */
               /* if (msgSleepBasic.getBreath() > 0 && (msgSleepBasic.getBreath() > maxBreathThreshold || msgSleepBasic.getBreath() < minBreathThreshold)) {
                    if (!redisTemplate.hasKey(RedisKeyUtil.getCsunSleepBreathAlert(sn))) {
                        //发送报警
                        DmcDeviceAlert dmcDeviceAlert = new DmcDeviceAlert();
                        OldmanBedRoomBuildingVo obrvo = new OldmanBedRoomBuildingVo();
                        int result = dmcDeviceAlertService.csunSleepAlertMsg(sn, dmcDeviceAlert, obrvo, CsunSleepConstant.BREATH_ALERT);
                        log.info("=====> dmcDeviceAlert = {}", dmcDeviceAlert.toString());
                        if (result > 0) {
                            dmcDeviceAlertService.sendDeviceAlertMsg(dmcDeviceAlert, obrvo);
                        }
                        redisTemplate.opsForValue().set(RedisKeyUtil.getCsunSleepBreathAlert(sn), csunSleepData, alertDurtion, TimeUnit.SECONDS);
                    }
                }
                if (msgSleepBasic.getHeartbeat() > 0 && (msgSleepBasic.getHeartbeat() > maxHeartbeatThreshold || msgSleepBasic.getHeartbeat() < minHeartbeatThreshold)) {
                    if (!redisTemplate.hasKey(RedisKeyUtil.getCsunSleepHeartbeatAlert(sn))) {
                        //发送报警
                        DmcDeviceAlert dmcDeviceAlert = new DmcDeviceAlert();
                        OldmanBedRoomBuildingVo obrvo = new OldmanBedRoomBuildingVo();
                        int result = dmcDeviceAlertService.csunSleepAlertMsg(sn, dmcDeviceAlert, obrvo, CsunSleepConstant.HEARTBEAT_ALERT);
                        log.info("=====> dmcDeviceAlert = {}", dmcDeviceAlert.toString());
                        if (result > 0) {
                            dmcDeviceAlertService.sendDeviceAlertMsg(dmcDeviceAlert, obrvo);
                        }
                        redisTemplate.opsForValue().set(RedisKeyUtil.getCsunSleepHeartbeatAlert(sn), csunSleepData, alertDurtion, TimeUnit.SECONDS);
                    }
                }*/



                    if(msgSleepBasic.getBreath() > 0 && msgSleepBasic.getHeartbeat() > 0 && alertDurtion > 0){


                        if((msgSleepBasic.getBreath() > maxBreathThreshold || msgSleepBasic.getBreath() < minBreathThreshold) || (msgSleepBasic.getHeartbeat() > maxHeartbeatThreshold || msgSleepBasic.getHeartbeat() < minHeartbeatThreshold)){


                            if (!redisTemplate.hasKey(RedisKeyUtil.getCsunSleepBreathAlert(sn))) {


                                //发送报警
                                DmcDeviceAlert dmcDeviceAlert = new DmcDeviceAlert();
                                OldmanBedRoomBuildingVo obrvo = new OldmanBedRoomBuildingVo();
                                int result = dmcDeviceAlertService.csunSleepAlertMsg(sn, dmcDeviceAlert, obrvo, CsunSleepConstant.BREATH_ALERT);
                                log.info("=====> dmcDeviceAlert = {}", dmcDeviceAlert.toString());
                                if (result > 0) {
                                    dmcDeviceAlertService.sendDeviceAlertMsg(dmcDeviceAlert, obrvo);
                                    dmcDeviceAlertService.sendLifeMsg(dmcDeviceAlert, obrvo, LifeConstant.YES_SOUND);
                                }
                                /**
                                 * @author  chisj
                                 * @date    2020-11-19
                                 * @desc    生命体征监测时间从秒改为分
                                 */
                                redisTemplate.opsForValue().set(RedisKeyUtil.getCsunSleepBreathAlert(sn), csunSleepData, alertDurtion, TimeUnit.MINUTES);
                            }
                        }
                    }
                }
//            }

            redisTemplate.opsForValue().set(RedisKeyUtil.getCsunSleepKey(csunSleepData.getDeviceNo()),
                    csunSleepData);

            // 入库
            saveCsunSleepData(csunSleepData);
            dmcDeviceAlertService.sendSleepDataByDeviceId(csunSleepData.getDeviceId());
            publishCsunSleepData(csunSleepData);

            publicGuoKang(csunSleepData.getDeviceNo(),
                    csunSleepData.getBreath(),
                    csunSleepData.getHeartbeat(),
                    "bed_touch");
        } else {
            new RuntimeException("csun sleep not load... [" + sn + "]");
        }

    }

    /**
     * 处理床垫消息
     *
     * @param msg
     */
    public void dealSleepMsg(String msg) {

        MsgSleepBed msgSleepBed = gson.fromJson(msg, MsgSleepBed.class);
        String sn = msgSleepBed.getMattessId();

        CsunSleepData csunSleepData = (CsunSleepData) redisTemplate.opsForValue()
                .get(RedisKeyUtil.getCsunSleepKey(sn));

        if (PublicUtil.isNotEmpty(csunSleepData)) {

        } else {
            new RuntimeException("csun sleep not load... [" + sn + "]");
        }

    }

    /**
     * 处理床垫报警消息
     *
     * @param msg
     */
    public void dealSleepAlarmMsg(String msg) {

        MsgSleepAlarm msgSleepAlarm = gson.fromJson(msg, MsgSleepAlarm.class);
        String sn = msgSleepAlarm.getMattessId();
        CsunSleepData csunSleepData = (CsunSleepData) redisTemplate.opsForValue()
                .get(RedisKeyUtil.getCsunSleepKey(sn));
        Long deviceId = csunSleepData.getDeviceId();
        DmcCsunSleepBind bindQuery = new DmcCsunSleepBind();
        bindQuery.setDeviceId(deviceId);
        bindQuery = dmcCsunSleepBindService.selectOne(bindQuery);
        if(bindQuery.getActionDuration() != null && bindQuery.getActionDuration() > 0){
            ACTION_DURATION = bindQuery.getActionDuration();
        }
        if (PublicUtil.isNotEmpty(csunSleepData)) {

            /**
             * 设置在线过期时间
             */
            refreshCsunSleepOnline(csunSleepData);

            csunSleepData.setStatus(DeviceStatusEnum.ONLINE.getKey());
            if (msgSleepAlarm.getType().equals(3)) {
                csunSleepData.setAction(1); // 已经翻身
                csunSleepData.setInBed(1);
                csunSleepData.setStatus(DeviceStatusEnum.ONLINE.getKey());
                Date currentDate = new Date();

                // 计算上一次和本次的体动间隔时间
                if ( csunSleepData.getActionTime() != null) {
                    long actionDuration = (currentDate.getTime() - csunSleepData.getActionTime().getTime()) / 1000;
                    csunSleepData.setActionDuration(actionDuration);
                }
                csunSleepData.setActionTime(currentDate);

                //查询设备绑定方式
                /*Long deviceId = csunSleepData.getDeviceId();
                DmcCsunSleepBind bindQuery = new DmcCsunSleepBind();
                bindQuery.setDeviceId(deviceId);
                bindQuery = dmcCsunSleepBindService.selectOne(bindQuery);*/
                //life绑定方式不推翻身报警
                if(bindQuery == null || !bindQuery.getBindType().equals(DeviceConstant.DEVICE_BIND_TYPE_LIFE)){
                    redisTemplate.opsForValue().set(CsunSleepConstant.ACTION_PREFIX + sn,
                            currentDate, ACTION_DURATION, TimeUnit.MINUTES);
                }
            }

            redisTemplate.opsForValue().set(RedisKeyUtil.getCsunSleepKey(csunSleepData.getDeviceNo()),
                    csunSleepData);

            // 入库
            saveCsunSleepData(csunSleepData);

            // 保存翻身数据
            saveCsunSleepActionData(csunSleepData);

            // 通过设备Id推送通知
            dmcDeviceAlertService.sendSleepDataByDeviceId(csunSleepData.getDeviceId());

            publishCsunSleepData(csunSleepData);

            publicGuoKang(csunSleepData.getDeviceNo(),
                    csunSleepData.getBreath(),
                    csunSleepData.getHeartbeat(),
                    "body_moving");
        } else {
            new RuntimeException("csun sleep not load... [" + sn + "]");
        }

    }

    /**
     * 处理床垫获取当前版本消息
     *
     * @param msg
     */
    public void dealSleepCurVerMsg(String msg) {

        MsgSleepCurrentVersion msgSleepCurrentVersion = gson.fromJson(msg, MsgSleepCurrentVersion.class);
        String sn = msgSleepCurrentVersion.getSn();

        CsunSleepData csunSleepData = (CsunSleepData) redisTemplate.opsForValue()
                .get(RedisKeyUtil.getCsunSleepKey(sn));

        if (PublicUtil.isNotEmpty(csunSleepData)) {

        } else {
            new RuntimeException("csun sleep not load... [" + sn + "]");
        }

    }

    /**
     * 处理床垫版本更新消息
     *
     * @param msg
     */
    public void dealSleepUdtVerMsg(String msg) {

        MsgSleepBed msgSleepBed = gson.fromJson(msg, MsgSleepBed.class);
        String sn = msgSleepBed.getMattessId();

        CsunSleepData csunSleepData = (CsunSleepData) redisTemplate.opsForValue()
                .get(RedisKeyUtil.getCsunSleepKey(sn));

        if (PublicUtil.isNotEmpty(csunSleepData)) {

        } else {
            new RuntimeException("csun sleep not load... [" + sn + "]");
        }

    }

    /**
     * 保存床垫数据
     *
     * @param csunSleepData
     */
    public void  saveCsunSleepData(CsunSleepData csunSleepData) {
        DmcCsunSleepData dmcCsunSleepData = new DmcCsunSleepData();
        DmcCsunSleepDataHi dmcCsunSleepDataHi = new DmcCsunSleepDataHi();
        BeanUtils.copyProperties(csunSleepData, dmcCsunSleepData);
        BeanUtils.copyProperties(csunSleepData, dmcCsunSleepDataHi);
        dmcCsunSleepDataService.update(dmcCsunSleepData);
        dmcCsunSleepDataHiService.save(dmcCsunSleepDataHi);
    }

    /**
     * 保存床垫历史数据
     *
     * @param csunSleepData
     */
    public void saveCsunSleepActionData(CsunSleepData csunSleepData) {

        DmcCsunSleepDataAction dmcCsunSleepDataAction = new DmcCsunSleepDataAction();
        BeanUtils.copyProperties(csunSleepData, dmcCsunSleepDataAction);
        dmcCsunSleepDataAction.setDuration(csunSleepData.getActionDuration());

        dmcCsunSleepDataActionService.save(dmcCsunSleepDataAction);
    }

    public void saveCsunSleepInBedData(CsunSleepData csunSleepData) {

        // 在离床间隔时间
        Date current = new Date();
        long bedDuration = (current.getTime() - csunSleepData.getBedTime().getTime()) / 1000;

        DmcCsunSleepDataInBed dmcCsunSleepDataInBed = new DmcCsunSleepDataInBed();
        BeanUtils.copyProperties(csunSleepData, dmcCsunSleepDataInBed);
        if (csunSleepData.getStatus().equals(DeviceStatusEnum.OFFLINE.getKey())) {
            dmcCsunSleepDataInBed.setInBed(2);
        }
        dmcCsunSleepDataInBed.setDuration(bedDuration);

        csunSleepData.setBedTime(current);
        csunSleepData.setBedDuration(bedDuration);
        redisTemplate.opsForValue().set(RedisKeyUtil.getCsunSleepKey(csunSleepData.getDeviceNo()),
                csunSleepData);

        dmcCsunSleepDataInBedService.save(dmcCsunSleepDataInBed);
    }

    public void publicGuoKang(String deviceNo, Integer breath, Integer heart, String status) {

        String gkTopic = "/products/mattress/" + deviceNo;
        String mzTopic = "mattress";

        String userId = dmcGuoKangClientService.selectByDeviceNo(deviceNo);
        if (PublicUtil.isEmpty(userId)) {
            log.info("=====> the user id is empty [{}]", deviceNo);
            return ;
        }

        if (breath.equals(-1) || heart.equals(-1)) {
            GuoKangData guoKangData = GuoKangPub.data.get(userId);
            if (PublicUtil.isNotEmpty(guoKangData)) {
                breath = guoKangData.getBreath();
                heart = guoKangData.getHeart();
            }
        } else {
            GuoKangData guoKangData = new GuoKangData();
            guoKangData.setBreath(breath);
            guoKangData.setHeart(heart);
            GuoKangPub.data.put(userId, guoKangData);
        }

        Map<String, Object> gkMap = Maps.newHashMap();
        Map<String, Object> mzMap = Maps.newHashMap();
        /* required; String; 产品型号见表一 */
        gkMap.put("product-mode", "MS005");
        mzMap.put("product-mode", "MS005");
        /* required; String; 设备编号 */
        mzMap.put("device-id", deviceNo);
        /* optional; String; 受试者编号，设备对应唯一受试者时 */
        /* required; String; 受试者编号，设备对应多个受试者时 */
        gkMap.put("user-id", userId);
        mzMap.put("user-id", userId);
        /* required; Number; 呼吸 */
        gkMap.put("breath", breath);
        mzMap.put("breath", breath);
        /* required; Number; 心率 */
        gkMap.put("heart", heart);
        mzMap.put("heart", heart);
        /* required; String;
            bed_off,离床
            bed_touch,在床
            body_moving 体动
            other 其他 */
        gkMap.put("status", status);
        mzMap.put("status", status);
        /* optional; Number; 0:清醒; 1:入睡; 2:浅睡; 3:深睡;4：其他 */
        gkMap.put("sleepFlag", 4);
        mzMap.put("sleepFlag", 4);
        /* required; String;  时间戳 */
        gkMap.put("time", DateUtil.dateToString(new Date()));
        mzMap.put("time", DateUtil.dateToString(new Date()));

        guoKangPub.sendMessage(gkTopic, gkMap);
        // minZhengPub.sendMessage(mzTopic, mzMap);
        mqttPushService.mqttBedPush(mzMap, "000", "mattress");
    }

    public void publishCsunSleepData(CsunSleepData csunSleepData) {

        MsgSleepReal msgSleepReal = new MsgSleepReal();
        BeanUtils.copyProperties(csunSleepData, msgSleepReal);

        /**
         * @date    2019-05-06
         * @author  chisj
         * @desc    避免一直给设备推送消息
         */
        String topic = "FRONT_CLIENT_" + csunSleepData.getDeviceNo();

        sleepMessageGateway.sendToMqtt(topic, 1,
                JSONObject.fromObject(msgSleepReal).toString());
    }

    /**
     * 处理设备log信息
     *
     * @param msg
     */
    private void dealLogMsg(String msg) {

        MsgLog msgLog = gson.fromJson(msg, MsgLog.class);

        /**
         * @date    2020-05-20
         * @author  chisj
         * @desc    采集设备日志
         */
        deviceLogUtils.print(msgLog);

        String sn = msgLog.getSn();
        String redisKey = RedisKeyUtil.getCsunSleepKey(sn);

        CsunSleepData csunSleepData = (CsunSleepData) redisTemplate.opsForValue()
                .get(redisKey);

        if (PublicUtil.isNotEmpty(csunSleepData)) {

            DmcDeviceLog dmcDeviceLog = new DmcDeviceLog();
            BeanUtils.copyProperties(msgLog, dmcDeviceLog);

            DmcCsunSleepVo dmcCsunSleepVo  = dmcCsunSleepBindService
                    .getCsunSleepBindByDeviceId(csunSleepData.getDeviceId());

            if (PublicUtil.isEmpty(dmcCsunSleepVo)) {
                new RuntimeException("csun gateway not exist...[" + sn + "]");
            }

            DeviceBindDto deviceBindDto = new DeviceBindDto();
            BeanUtils.copyProperties(dmcCsunSleepVo, deviceBindDto);
            OldmanBedRoomBuildingVo obrvo = deviceUtils.getOldmanBedRoomBuildingVo(deviceBindDto);
            if (PublicUtil.isNotEmpty(obrvo)) {
                if (dmcCsunSleepVo.getBindType().equals(DmcCsunSleepBindTypeEnum.OLDMAN.getKey())) {
                    dmcCsunSleepVo.setOldmanName(obrvo.getOldmanName());
                    dmcCsunSleepVo.setLocation(obrvo.getLocation());
                }
                // 绑定床位, 老人信息和位置根据床位获取
                if (dmcCsunSleepVo.getBindType().equals(DmcCsunSleepBindTypeEnum.BED.getKey())) {
                    dmcCsunSleepVo.setOldmanName(obrvo.getOldmanName());
                    dmcCsunSleepVo.setLocation(obrvo.getLocation());
                    dmcCsunSleepVo.setOldmanId(obrvo.getOldmanId());
                }
            }

            // 获取设备的位置
            dmcDeviceLog.setDeviceId(csunSleepData.getDeviceId());
            dmcDeviceLog.setDeviceNo(dmcCsunSleepVo.getDeviceNo());
            dmcDeviceLog.setGroupId(dmcCsunSleepVo.getGroupId());
            dmcDeviceLog.setDeviceName(dmcCsunSleepVo.getDeviceName());
            dmcDeviceLog.setDeviceLocation(dmcCsunSleepVo.getLocation());

            // 存储日志
            dmcDeviceLogService.save(dmcDeviceLog);

        } else {
            new RuntimeException("csun sleep not load... [" + sn + "]");
        }
    }



}
